-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
unconstrained type parameters are consistently checked for {} | null | undefined
in strictNullChecks
#59059
base: main
Are you sure you want to change the base?
Conversation
@typescript-bot pack this |
@@ -20,8 +20,8 @@ function isDefined<T>(value: T | undefined | null | void): value is T { | |||
> : ^^^^^^^^^ | |||
>value !== null : boolean | |||
> : ^^^^^^^ | |||
>value : (T & {}) | null | |||
> : ^^^^^^^^^^^^^^^ | |||
>value : (T & ({} | null)) | null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this seems to be the only weirder/"I may need to fix that" break that happens in the test suite. This test pre-dates #49119, which adds "An unconstrained type parameter is no longer assignable to {}" and was the cause of the original regression that this PR fixes, so the code in this test doesn't do what the original author probably intended.
Hey @iisaduan, I've packed this into an installable tgz. You can install it for testing by referencing it in your
and then running There is also a playground for this build and an npm module you can use via |
@typescript-bot test it |
Hey @iisaduan, the results of running the DT tests are ready. Everything looks the same! |
@iisaduan Here are the results of running the user tests with tsc comparing Something interesting changed - please have a look. Details
|
@iisaduan Here they are:
tscComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
Developer Information: |
@iisaduan Here are the results of running the top 400 repos with tsc comparing Something interesting changed - please have a look. Details
|
With this PR, this lint check is necessary, as it was what was causing the self-check to fail earlier https://github.com/microsoft/TypeScript/actions/runs/9751008069/job/26911678446 |
So one of the things that no longer works is the following: function f<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
// ~~~
// error! 'obj' is possibly 'null' or 'undefined'.
} One of the reasons we've typically said that this is okay is because f(undefined, "hello");
// ~~~~~~~
// error! Argument of type 'string' is not assignable to parameter of type 'never'. I know @ahejlsberg was considering changing this for other reasons around the time that #56652 was out. Maybe he has some thoughts here or can give some pointers. I think we can fix #50603 well enough without disrupting the behaviors in place, but I'd have to take a deeper look to help out there. |
Thanks for the insight! I think so too, I will fix that. Those test cases looked alright at first, but after you brought the above up, I was reminded that the following is similarish and fine function f<T>(obj: T) {
for (const key in obj) {
obj[key]; // no errors
}
} |
@typescript-bot test it |
Hey @iisaduan, the results of running the DT tests are ready. Everything looks the same! |
@iisaduan Here are the results of running the user tests with tsc comparing Something interesting changed - please have a look. Details
|
@iisaduan Here they are:
tscComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
Developer Information: |
@iisaduan Here are the results of running the top 400 repos with tsc comparing Something interesting changed - please have a look. Details
|
@DanielRosenwasser interestingly, this is also a current issue (5.5.3, playground) when function f<T extends {} | null | undefined , K extends keyof T>(obj: T, key: K) {
return obj[key];
~~~
!!! error TS18049: 'obj' is possibly 'null' or 'undefined'.
~~~~~~~~
!!! error TS2536: Type 'K' cannot be used to index type '{}'.
} |
{} | null | undefined
in strictNullChecks
{} | null | undefined
in strictNullChecks
@typescript-bot test top400 |
@iisaduan Here are the results of running the user tests with tsc comparing Something interesting changed - please have a look. Details
|
Looks like #50603 is being addressed in #59352 (and I'll comment on that separately there). Meanwhile, in the example function f<T, K extends keyof T>(obj: T, key: K) {
return obj[key]; // Ok
}
function g<T extends {} | null | undefined , K extends keyof T>(obj: T, key: K) {
return obj[key]; // Error, 'obj' is possibly 'null' or 'undefined'.
} the second error really shouldn't be there. As @DanielRosenwasser points out above, for any |
fixes #50603
This behavior is due to a case that was unchecked in #49119. (Relevant summary of 49119:
{}
";unknown
, which is equivalent toextends {} | null | undefined
;The behavior was previously inconsistent, as shown in the cases below (5.5.3 playground):
Implementation:
This PR
TypeFacts
returns for unconstrained parameters. Instead of finding that unconstrained type parameters haveUnknownFacts
, we allow unconstrained type parameters to have all facts. SinceUnknownFacts = AllFacts & ~UndefinedOrNull
, this change means that unconstrained type parameters now have the possibility to be treated asundefined | null
even when not explicitly unioned.checkNonNullExpression
Considerations left
-- in
function f<T, U extends T>
,U
is not an unconstrained parameter-- (CFA needed?) to check previously ok cases (see
tests/baselines/reference/isomorphicMappedTypeInference.errors.txt
)--
const b = "foo" in obj[key];
is no longer okay when we have parameter(obj: T)
(seekeyofAndIndexedAccessErrors.txt
)